#pragma once
#include <common_header.h>
#include <gfx/vk/vk_common.h>

namespace primal
{
    namespace gfx
    {
        constexpr u32 default_queue_family_index{};
        constexpr u32 default_transfer_queue_family_index{};
        constexpr u32 max_queue_count{ 1u };

        enum MemoryPropertyTypes
        {
            Default,
            Upload
        };

        struct VkDeviceClass : VolkDeviceTable
        {
            VkDevice _dev;
            VkResult CreateCommandPool(const VkCommandPoolCreateInfo*, VkCommandPool*);
            VkResult AllocateCommandBuffers(const VkCommandBufferAllocateInfo*, VkCommandBuffer*);
            void GetDeviceQueue(uint32_t, uint32_t, VkQueue*);
            VkResult CreateSwapchainKHR(const VkSwapchainCreateInfoKHR*, VkSwapchainKHR*);
            VkResult GetSwapchainImagesKHR(VkSwapchainKHR, uint32_t*, VkImage*);
            VkResult CreateRenderPass(const VkRenderPassCreateInfo*, VkRenderPass*);
            VkResult CreatePipelineLayout(const VkPipelineLayoutCreateInfo*, VkPipelineLayout*);
            VkResult CreateGraphicsPipelines(VkPipelineCache, uint32_t, const VkGraphicsPipelineCreateInfo*, VkPipeline*);
            VkResult CreateImageView(const VkImageViewCreateInfo*, VkImageView*);
            VkResult CreateFramebuffer(const VkFramebufferCreateInfo*, VkFramebuffer*);
            VkResult AcquireNextImageKHR(VkSwapchainKHR, uint64_t, VkSemaphore, VkFence, uint32_t*);
            VkResult QueuePresentKHR(VkQueue, const VkPresentInfoKHR*);
            VkResult CreateShaderModule(const VkShaderModuleCreateInfo*, VkShaderModule*);
            VkResult CreateSemaphore(VkSemaphore*);
            VkResult CreateFence(VkFence*);
            VkResult WaitForFences(uint32_t, const VkFence*, VkBool32, uint64_t);
            VkResult WaitForFences(const VkFence*);
            VkResult ResetFences(uint32_t, const VkFence*);
            VkResult ResetFences(const VkFence*);
            VkResult ResetCommandBuffer(VkCommandBuffer, VkCommandBufferResetFlags);
            VkResult ResetCommandPool(VkCommandPool, VkCommandPoolResetFlags);
            PFN_vkVoidFunction GetProcAddr(const char*);
            VkResult CreateDescriptorPool(const VkDescriptorPoolCreateInfo*, VkDescriptorPool*);
            VkResult CreateBuffer(const VkBufferCreateInfo*, VkBuffer*);
            VkResult CreateBufferEx(VkDeviceSize size, VkBufferUsageFlags usage, MemoryPropertyTypes type, VkBuffer& buf);
            void DestoryBuffer(VkBuffer);
            VkResult AllocateeMemory(const VkMemoryAllocateInfo*, VkDeviceMemory*);
            VkResult AllocateDefaultMemory(VkDeviceMemory&, VkDeviceSize);
            VkResult AllocateUploadMemory(VkDeviceMemory&, VkDeviceSize);
            void FreeMemory(VkDeviceMemory);
            VkResult MapMemory(VkDeviceMemory, VkDeviceSize, VkDeviceSize, VkMemoryMapFlags, void**);
            void UnmapMemory(VkDeviceMemory);
            VkResult BindBufferMemory(VkBuffer, VkDeviceMemory, VkDeviceSize);
            VkResult CreateDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo*, VkDescriptorSetLayout*);
            VkResult AllocateDescriptorSets(const VkDescriptorSetAllocateInfo*, VkDescriptorSet*);
            void UpdateDescriptorSets(uint32_t, const VkWriteDescriptorSet*, uint32_t, const VkCopyDescriptorSet*);

        };

        struct render_context
        {
            VkRenderPass render_pass;
            VkPipeline pipeline;

        };

        enum RENDERE_PASS_TYPE
        {
            UI,
            RENDER,
            MAX_COUNT
        };

        bool initialize();
        //VolkDeviceTable& device_fun();
        VkAllocationCallbacks* alloc_cbk();
        VkInstance vk_instance();
        VkPhysicalDevice phy();
        VkDeviceClass& dev();
        VkQueue graphics_queue();
        VkQueue transfer_queue();
        void GetPhysicalDeviceSurfaceFormats(VkSurfaceKHR);
        VkDescriptorPool desc_pool();
        VkRenderPass get_pass(RENDERE_PASS_TYPE);
        void shutdown();
    } // namespace gfx

} // namespace primal
